﻿using System;
using System.Collections.Generic;
using System.Linq;
using Fuse8.DomainFramework.Common.Utilities;
using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.Practices.Domain;
using Fuse8.DomainFramework.Practices.Domain.Interfaces;
using Fuse8.DomainFramework.Practices.SystemFacade;
using NUnit.Framework;

namespace UnitTests
{
	[TestFixture]
	public class EntityGeneratorTests
	{
		[Test]
		public void OnePropertyClassValidTest ()
		{
			var data = EntityGenerator<TestEntity>.Create(); 
			Assert.That(data, Is.Not.Null);
			data.Name = "test";
			Assert.That(data.Name, Is.EqualTo("test"));
		}

		[Test]
		public void OnePropertyClassExceptionTest()
		{	
			var data = EntityGenerator<TestEntity>.Create();
			Assert.That(data, Is.Not.Null);
			Assert.Throws(Is.InstanceOf<PropertyNotLoadedException>(), () => { var a = data.Name; });
		}

		[Test]
		public void FieldTrackerGenerated ()
		{
			var data = EntityGenerator<TestEntity>.Create();
			Assert.That(data, Is.InstanceOf<Fuse8.DomainFramework.Practices.Domain.Interfaces.IFieldTracker>());
		}

		[Test]
		public void FieldTrackerEnabled ()
		{
			var data = EntityGenerator<TestEntity>.Create();
			Assert.That(((Fuse8.DomainFramework.Practices.Domain.Interfaces.IFieldTracker)data).IsTrackingDisabled, Is.False);
		}

		[Test]
		public void FieldTrackerNameUpdated()
		{
			var data = EntityGenerator<TestEntity>.Create();
			data.Name = "!";
			CollectionAssert.AreEquivalent(((Fuse8.DomainFramework.Practices.Domain.Interfaces.IFieldTracker)data).GetUpdatedFields(), new[] { "Name" });
		}

		[Test]
		public void FieldTrackerDisabling()
		{
			var data = EntityGenerator<TestEntity>.Create();
			var fieldTracker = (Fuse8.DomainFramework.Practices.Domain.Interfaces.IFieldTracker)data;
			fieldTracker.IsTrackingDisabled = true;
			data.Name = "!";
			CollectionAssert.IsEmpty(fieldTracker.GetUpdatedFields());
		}

		[Test]
		public void FieldTrackerSameValue()
		{
			var data = EntityGenerator<TestEntity>.Create();
			var fieldTracker = (Fuse8.DomainFramework.Practices.Domain.Interfaces.IFieldTracker)data;
			fieldTracker.IsTrackingDisabled = true;
			data.Name = "!";
			CollectionAssert.IsEmpty(fieldTracker.GetUpdatedFields());
			fieldTracker.IsTrackingDisabled = false;
			data.Name = "!";
			CollectionAssert.IsEmpty(fieldTracker.GetUpdatedFields());
		}

        [Test]
        public void IsClonable()
        {
            var data = EntityGenerator<TestEntity>.Create();
            data.Name = "Test";
            var clone = data.NormalClone();
            Assert.That(clone, Is.Not.Null);
            Assert.That(clone.Name, Is.EqualTo("Test"));
        }

		[Test]
		public void OnePropertyInterfaceValidTest()
		{
			var data = EntityGenerator<ITestEntity>.Create();
			Assert.That(data, Is.Not.Null);
			data.Name = "test";
			Assert.That(data.Name, Is.EqualTo("test"));			
		}

		[Test]
		public void ComplexEntityInnerEntityNullTest()
		{
			var data = EntityGenerator<IComplexEntity>.Create();
			Assert.That(data.TestEntity, Is.Null);
		}

		[Test]
		public void ListPropertiesTest()
		{
			var data = EntityGenerator<TestListEntity>.Create();
			Assert.That(data.IEnumerable, Is.Empty);
			Assert.That(data.IList, Is.Empty);
			Assert.That(data.List, Is.Empty);
		}

		[Test]
		public void ListPropertiesInterfaceTest()
		{
			var data = EntityGenerator<ITestListEntity>.Create();
			Assert.That(data.IEnumerable, Is.Empty);
			Assert.That(data.IList, Is.Empty);
			Assert.That(data.List, Is.Empty);
		}

		[Test]
		public void LoadedEntityContainerTest()
		{
			var data = EntityGenerator<TestEntity>.Create();
			Assert.That(((ILoadedEntityContainer)data).GetLoadedEntities(typeof(TestEntity).TypeHandle), Is.Empty);
			Assert.That(((ILoadedEntityContainer)data).GetLoadedEntities(typeof(TestEntity).TypeHandle), Is.Empty);
		}

		[Test]
		public void NullableBoolPropertyTest()
		{
			var data = EntityGenerator<TestEntity>.Create();
			data.NullableBoolProperty = null;
			Assert.That(data.NullableBoolProperty, Is.EqualTo(null));
			data.NullableBoolProperty = true;
			Assert.That(data.NullableBoolProperty, Is.EqualTo(true));
		}
	}
    [Serializable]
	public class TestEntity : Int32EntityObject
	{
		public virtual string Name { get; set; }
		public virtual string Second { get; set; }
		public virtual bool? NullableBoolProperty { get; set; }
	}

	public class TestListEntity
	{
		public virtual IEnumerable<TestEntity> IEnumerable { get; set; }
		public virtual IList<TestEntity> IList { get; set; }
		public virtual List<TestEntity> List { get; set; }
	}

	public interface ITestListEntity
	{
		IEnumerable<TestEntity> IEnumerable { get; set; }
		IList<TestEntity> IList { get; }
		List<TestEntity> List { get; set; }
	}

	public interface ITestEntity : IEntityObject<int>
	{
		string Name { get; set; }
	}

	public interface IComplexEntity : IEntityObject<int>
	{
		string Name { get; set; }
		TestEntity TestEntity { get; set; }
	}
}